package com.lxm.test;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class BlockingQueue {
    private int size = 0;
    private int maxLength = 10;
    private int[] array;
    private ReentrantLock lock = new ReentrantLock();
    private Condition notEmpty = lock.newCondition();
    private Condition full = lock.newCondition();

    public BlockingQueue() {
        this(10);
    }

    public BlockingQueue(int maxLength) {
        this.maxLength = maxLength;
        this.array = new int[maxLength];
    }


    public void put(int element) {
        lock.lock();
        try {
            while (size == maxLength) {
                try {
                    full.await();
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
            }
            array[size++] = element;
            System.out.println(Thread.currentThread().getName() + " put ele " + element);
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }


    public int take() {
        lock.lock();
        try {
            while (size == 0) {
                try {
                    notEmpty.await();
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
            }
            int e = array[--size];
            System.out.println(Thread.currentThread().getName() + " take ele " + e);
            full.signal();
            return e;
        } finally {
            lock.unlock();
        }
    }


    class Produce implements Runnable {
        private BlockingQueue blockingQueue;

        public Produce(BlockingQueue blockingQueue) {
            this.blockingQueue = blockingQueue;
        }


        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                blockingQueue.put(i);
            }
        }
    }

    class Consumer implements Runnable {
        private BlockingQueue blockingQueue;

        public Consumer(BlockingQueue blockingQueue) {
            this.blockingQueue = blockingQueue;
        }

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                blockingQueue.take();
            }
        }
    }

    public static void main(String[] args) {
        BlockingQueue blockingQueue = new BlockingQueue(1);
//        blockingQueue.offer(1);
//        blockingQueue.offer(2);
//        int e1 = blockingQueue.poll();
//        int e2 = blockingQueue.poll();

        new Thread(blockingQueue.new Produce(blockingQueue), "producer").start();
        new Thread(blockingQueue.new Consumer(blockingQueue), "consumer").start();
    }
}
